
#include <System/IO/FileStream.h>
#include <System/Int32.h>
#include <System/Diagnostics/Debug.h>

#include "Texture2D.h"
//#include "../RGame.h"

#ifdef ref
#undef ref
#endif
#ifdef out
#undef out
#endif

#include <vendor/png/picoPNG.h>

#if Windows
#include <variant_iostream.h>
#include <fstream>
#include <GL/glut.h>
#else
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <UndefCSharpKeywords.h>
#include <jni.h>
#include <android/log.h>
#define  LOG_TAG    "jnitest"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

#endif

static void checkGlError(const char* op)
{
    for (GLint error = glGetError(); error; error = glGetError())
	{
#if Windows

#elif Android
		LOGI("after %s() glError (0x%x)\n", op, error);
#endif
    }
}

using namespace Riccsson::System;
using namespace Riccsson::System::Diagnostics;
using namespace Riccsson::Xna::Framework::Graphics;

uint Texture2D::_generated_texture_id = 0;

// ------------------------------------------------------------------------
void loadFile(std::vector2<unsigned char>& buffer, Riccsson::System::IO::Stream* file) //designed for loading files from hard disk in an std::vector
{
	//std::ifstream file(filename, std::ios::in|std::ios::binary|std::ios::ate);
	//
	////get filesize
	//std::streamsize size = 0;
	//if(file.seekg(0, std::ios::end).good()) size = file.tellg();
	//if(file.seekg(0, std::ios::beg).good()) size -= file.tellg();

	//read contents of the file into the vector
	if(file->Length > 0)
	{
		buffer.resize((size_t)file->Length);
		Debug::WriteLine("buffer.resize() Calling.");
		Debug::WriteLine(Int32((int)file->Length).ToString());

		file->Read((byte*)(&buffer[0]), 0, file->Length);
		Debug::WriteLine("file->Read() Calling.");
	}
	else buffer.clear();
}


// ------------------------------------------------------------------------
GC_PTR<Texture2D> Texture2D::FromStream(GraphicsDevice* graphicsDevice, Riccsson::System::IO::Stream* stream)
{
	Debug::WriteLine( string("FromStream(..., ") + stream->Length + ")");

	unsigned int generatedTexture_out(0);
	int width(0);
	int height(0);

//#if Windows
//	int status = LoadGLTextures(stream->_filename->c_str(), generatedTexture_out, width, height);
//#else
//	throw;
//#endif
	
	Debug::WriteLine("FromStream() Calling.");

	//load and decode
	std::vector2<unsigned char> buffer, image;
	loadFile(buffer, stream);
	Debug::WriteLine("SpriteBatch created.");
	unsigned long w, h;
	int error = decodePNG(image, w, h, buffer.empty() ? 0 : &buffer[0], (unsigned long)buffer.size());
	width = (int)w;
	height = (int)h;

	Debug::WriteLine(string("decodePNG error code: ") + error);

	// Error check.
	if(error != 0)
	{
		Debug::WriteLine("Decode PNG returned error code:");
		Debug::WriteLine(Int32(error).ToString());
	}

	//// Test write on PNG.
	//for (int i = 0; i < image.size(); i++)
	//{
	//	image[i] = (unsigned char)i;
	//}
	
	// Convert decoded png texture to an OpenGL texture here.
	GLubyte* textureImage = (GLubyte*)&image[0];
	bool hasAlpha = true;
	
	GLuint texture( 999 );
	glGenTextures(1, &texture);
    checkGlError("glGenTextures");
	System::Diagnostics::Debug::WriteLine(string("glGenTextures return id: ") + texture);
	
	glBindTexture(GL_TEXTURE_2D, texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) textureImage);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);

	generatedTexture_out = (GLuint)texture;

	// TODO: How to get id?
	//glGenTextures(1, &generatedTexture_out);          // Create The Texture.

	// Typical Texture Generation Using Data From The Bitmap.
	//glBindTexture(GL_TEXTURE_2D, generatedTexture_out);

	//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	//glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width, height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, textureImage);
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //glEnable(GL_TEXTURE_2D);
	//glShadeModel(GL_ALPHA);

	GC_PTR<Texture2D> output( new Texture2D(generatedTexture_out, width, height) );
	return output;
}
